package fr.gdi.android.news.utils;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import fr.gdi.android.news.ShareReceiverProxyAdapter;
import fr.gdi.android.news.ShareReceiverProxyAdapter.ShareReceiverProxy;
import fr.gdi.android.news.utils.Constants.Configuration;
import fr.gdi.android.news.utils.Constants.Preferences;

public final class PreferenceUtils
{
    private PreferenceUtils()
    {
    }
    
    public static int getUpdateInterval(Context context)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String interval = prefs.getString(Preferences.UPDATE_INTERVAL, Preferences.DEFAULT_UPDATE_INTERVAL);
        return Integer.parseInt(interval);
    }
    
    public static void setUpdateInterval(Context context, int interval)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor edit = prefs.edit();
        edit.putString(Preferences.UPDATE_INTERVAL, new Integer(interval).toString());
        edit.commit();
    }
    
    public static void setInt(Context context, String key, int value)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor edit = prefs.edit();
        edit.putInt(key, value);
        edit.commit();
    }
    
    
    public static Integer getIntFromStringPreference(Context ctx, String pref, Integer appWidgetId, String defaultValue)
    {
        defaultValue = TextUtils.isEmpty(defaultValue) ? "0" : defaultValue;
        
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        
        if (appWidgetId != null)
        {
            defaultValue = Integer.toString(getIntFromStringPreference(ctx, pref, null));
            pref = getWidgetPreferenceKey(pref, appWidgetId);
        }
        
        try
        {
            String val = prefs.getString(pref, defaultValue);
            return Integer.parseInt(val);
        }
        catch (NumberFormatException e)
        {
            return Integer.parseInt(defaultValue);
        }
    }
    
    public static Integer getIntFromStringPreference(Context ctx, String pref, Integer appWidgetId)
    {
        String defaultValue = "0";
        return getIntFromStringPreference(ctx, pref, appWidgetId, defaultValue);
    }
    
    public static String getBackground(Context ctx, Integer appWidgetId)
    {
        return getStringPreference(ctx, Preferences.BACKGROUND, appWidgetId, Configuration.DARK);
    }
    
    public static String getStringPreference(Context ctx, String pref, Integer appWidgetId)
    {
        String defaultValue = null;
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        if (appWidgetId != null)
        {
            defaultValue = getStringPreference(ctx, pref, null, defaultValue);
            pref = getWidgetPreferenceKey(pref, appWidgetId);
        }
        
        return prefs.getString(pref, defaultValue);
    }
    
    public static String getStringPreference(Context ctx, String pref, Integer appWidgetId, String defaultValue)
    {
        String s = getStringPreference(ctx, pref, appWidgetId);
        return TextUtils.isEmpty(s) ? defaultValue : s;
    }
    
    public static void setStringPreference(Context ctx, String key, String value)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        Editor editor = prefs.edit();
        editor.putString(key, value);
        editor.commit();
    }
    
    public static String getWidgetPreferenceKey(String pref, int appWidgetId)
    {
        return Preferences.WIDGET_PREF_SETTINGS + appWidgetId + "_" + pref;
    }
    
    public static String getWidgetTitle(Context ctx, Integer appWidgetId)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        return prefs.getString(Preferences.WIDGET_TITLE_PREF + appWidgetId, ctx.getString(Preferences.DEFAULT_WIDGET_TITLE_ID));
    }
    
    public static int getIntPreference(Context ctx, String key, Integer defaultValue, Integer appWidgetId)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        
        if (appWidgetId != null)
        {
            defaultValue = getIntPreference(ctx, key, defaultValue, null);
            key = getWidgetPreferenceKey(key, appWidgetId);
        }
        
        return prefs.getInt(key, defaultValue);
    }
    
    public static long getLong(Context ctx, String key)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        return prefs.getLong(key, 0);
    }
    
    public static void setLong(Context ctx, String key, long value)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        Editor editor = prefs.edit();
        editor.putLong(key, value);
        editor.commit();
    }
    
    public static void setWidgetTitle(Context ctx, Integer appWidgetId, String title)
    {
        if (TextUtils.isEmpty(title)) return;
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        Editor editor = prefs.edit();
        editor.putString(Preferences.WIDGET_TITLE_PREF + appWidgetId, title);
        editor.commit();
    }
    
    public static void dropSettings(Context context, int[] appWidgetIds)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        Map<String, ?> all = prefs.getAll();
        for (String k : all.keySet())
        {
            for (int appWidgetId : appWidgetIds)
            {
                if (k.startsWith(Preferences.WIDGET_PREF_SETTINGS + appWidgetId + "_"))
                {
                    editor.remove(k);
                }
                editor.remove(Preferences.WIDGET_TITLE_PREF + appWidgetId);
                editor.remove(Preferences.LAST_UPDATE + appWidgetId);
            }
        }
        editor.commit();
    }
    
    public static int getCropLength(Context ctx, Integer appWidgetId)
    {
        return getIntFromStringPreference(ctx, Preferences.CROP_DESCRIPTION_KEY, appWidgetId);
    }
    
    public static boolean getBooleanPreference(Context ctx, String key)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        return prefs.getBoolean(key, false);
    }
    
    public static boolean getBooleanPreference(Context ctx, String key, Integer appWidgetId)
    {
        return getBooleanPreference(ctx, key, appWidgetId, false);
    }
    
    public static boolean getBooleanPreference(Context ctx, String key, Integer appWidgetId, boolean b)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        
        boolean defaultValue = false || b;
        if (appWidgetId != null)
        {
            defaultValue = getBooleanPreference(ctx, key, null, false);
            key = getWidgetPreferenceKey(key, appWidgetId);
        }
        
        return prefs.getBoolean(key, defaultValue);
    }
    
    public static String getPreferredAction(Context context)
    {
        String preferredAction = PreferenceUtils.getStringPreference(context, Constants.Preferences.ON_TAP_ACTION, null);
        return TextUtils.isEmpty(preferredAction) ? Configuration.USE_BUILTIN_BROWSER : preferredAction;
    }
    
    public static void setBooleanPreference(Context context, String key, boolean val)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        editor.putBoolean(key, val);
        editor.commit();
    }
    
    public static void savePreferences(Context context, String filename) throws Exception
    {
        String NL = System.getProperty("line.separator");
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String[] keys = Preferences.SHARED_PREFERENCES;
        Map<String, ?> values = prefs.getAll();
        StringBuilder content = new StringBuilder("<?xml version='1.0' encoding='UTF-8' ?>").append(NL).append("<preferences>").append(NL);
        for (int i = 0, c = keys.length; i < c; i++)
        {
            String key = keys[i];
            Object value = values.get(key);
            content.append("    <preference key='").append(key).append("' value='").append(value).append("' />").append(NL);
        }
        content.append("</preferences>").append(NL);
        IOUtils.writeFile(IOUtils.EXTERNAL_STORAGE, TextUtils.isEmpty(filename) ? "preferences.xml" : filename, content.toString());
    }
    
    public static void restorePreferences(Context context, File file) throws Exception
    {
        final Map<String, String> map = new HashMap<String, String>();
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        XMLReader saxReader = parser.getXMLReader();
        saxReader.setContentHandler(new DefaultHandler() {
            @Override
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
            {
                if ("preference".equals(localName))
                {
                    String key = attributes.getValue(attributes.getIndex("key"));
                    String value = attributes.getValue(attributes.getIndex("value"));
                    map.put(key, value);
                }
            }
            
        });
        // saxReader.setErrorHandler(new DefaultHandler());
        saxReader.parse(new InputSource(new FileReader(file)));
        
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        for (String key : map.keySet())
        {
            try
            {
                setPreferenceValue(key, map.get(key), editor);
            }
            catch (Exception e)
            {
                // swallow?
                Log.e(IOUtils.class.getName(), "Preference " + key + "=" + map.get(key) + " NOT restored", e);
            }
        }
        editor.commit();
    }
    
     
    
    private static List<String> INTEGERS = Arrays.asList(new String[] { Preferences.HEADLINE_COLOR, Preferences.SUMMARY_COLOR, Preferences.FOOTER_COLOR,
            Preferences.WIDGET_TITLE_COLOR, Preferences.THUMB_SIZE, Preferences.THUMBNAIL_AT_RIGHT, Preferences.PARSE_DESCRIPTION, });
    private static List<String> BOOLEANS = Arrays.asList(new String[] { Preferences.MOBILIZER_SHOW_IMAGES, Preferences.CAPITALIZE_KEY, Preferences.HIDE_FOOTER,
            Preferences.USE_12_HOUR, Preferences.SHOW_IMAGES, Preferences.CLEAR_CACHE_ON_EXIT, Preferences.HIDE_HEADER, Preferences.REGULAR_HEADLINE, 
            //MIN_THUMB_WIDTH,
            });
    
    private static void setPreferenceValue(String key, String v, Editor editor)
    {
        if (INTEGERS.contains(key))
        {
            editor.putInt(key, Integer.parseInt(v));
        }
        else if (BOOLEANS.contains(key))
        {
            editor.putBoolean(key, Boolean.parseBoolean(v));
        }
        else
        {
            editor.putString(key, v);
        }
    }
    
    public static void setPreference(Context context, Preference pref, String key)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        
        key = TextUtils.isEmpty(key) ? pref.getKey() : key;
        if (pref instanceof CheckBoxPreference)
        {
            ((CheckBoxPreference) pref).setChecked(prefs.getBoolean(key, false));
        }
        else if (pref instanceof ListPreference)
        {
            ((ListPreference) pref).setValue(prefs.getString(key, null));
        }
        else if (pref instanceof EditTextPreference)
        {
            ((EditTextPreference) pref).setText(prefs.getString(key, null));
        }
    }
    
    public static void applyDefaults(Context context, Integer appWidgetId, boolean applyBackground)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        for (String pref : Preferences.PER_WIDGET_PREFERENCES)
        {
            String widgetPref = PreferenceUtils.getWidgetPreferenceKey(pref, appWidgetId);
            if (BOOLEANS.contains(pref))
            {
                boolean b = prefs.getBoolean(pref, false);
                editor.putBoolean(widgetPref, b);
            }
            else if (INTEGERS.contains(pref))
            {
                int i = prefs.getInt(pref, 0);
                editor.putInt(widgetPref, i);
            }
            else
            {
                if (!applyBackground && TextUtils.equals(Preferences.BACKGROUND, pref))
                {
                    continue;
                }
                String s = prefs.getString(pref, null);
                editor.putString(widgetPref, s);
            }
        }
    }
    
    public static void setDefaults(Context context, Integer appWidgetId)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        for (String pref : Preferences.PER_WIDGET_PREFERENCES)
        {
            String widgetPref = PreferenceUtils.getWidgetPreferenceKey(pref, appWidgetId);
            if (BOOLEANS.contains(pref))
            {
                boolean b = prefs.getBoolean(widgetPref, false);
                editor.putBoolean(pref, b);
            }
            else if (INTEGERS.contains(pref))
            {
                int i = prefs.getInt(widgetPref, 0);
                editor.putInt(pref, i);
            }
            else
            {
                String s = prefs.getString(widgetPref, null);
                editor.putString(pref, s);
            }
        }
        editor.commit();
    }
    
    public static String getHeadlineColorKey(String feedName)
    {
        return Preferences.HEADLINE_COLOR + "_" + feedName;
    }
    
    public static List<ShareReceiverProxy> getShareActivities(Context ctx)
    {
        List<String> disabledActivities = getDisabledShareActivities(ctx);
        
        final PackageManager packageManager = ctx.getPackageManager();
        final Intent intent = new Intent(Constants.Actions.SHARE);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, 0);
        List<ShareReceiverProxyAdapter.ShareReceiverProxy> proxies = new ArrayList<ShareReceiverProxyAdapter.ShareReceiverProxy>(); 
        if ( list.size() > 0 ) 
        {
            for (int u = 0; u < list.size(); u++)
            {
                ResolveInfo info = list.get(u);
                ActivityInfo activityInfo = info.activityInfo;

                Drawable icon = info.loadIcon(packageManager);
                String label = info.loadLabel(packageManager).toString();
                String appName = activityInfo.applicationInfo.loadLabel(packageManager).toString();
                String receiverName = activityInfo.name;
                String receiverPackage = activityInfo.packageName;
                
                ShareReceiverProxy item = new ShareReceiverProxy(label, appName, icon, receiverName, receiverPackage);
                if ( disabledActivities.contains(receiverPackage + receiverName) ) item.setDisabled(true); 
                proxies.add(item);
            }
        }
        return proxies;
    }
    
    public static List<String> getDisabledShareActivities(Context ctx)
    {
        List<String> activities = new ArrayList<String>();
        
        String serialized = getStringPreference(ctx, Preferences.DISABLED_SHARE_ACTIVITIES, null);
        
        if ( !TextUtils.isEmpty(serialized) )
        {
            return Arrays.asList(TextUtils.split(serialized, ";"));
        }
        
        return activities;
    }

    public static String URL_SEPARATOR = "\t\t";
    public static void addStringPreference(Context context, String pref, String url)
    {
        String v = getStringPreference(context, pref, null);
        if ( TextUtils.isEmpty(v) )
        {
            v = url;
        }
        else 
        {
            v += URL_SEPARATOR + url;
        }
        setStringPreference(context, pref, v);
    }
    
    public static void removePreference(Context context, String key)
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = prefs.edit();
        editor.remove(key);
    }
}
